<?php
/**
* M PHP Framework
* @package      M
* @subpackage   DB_DataObject_Advgenerator
*/
/**
* M PHP Framework
*
* DB_DataObject_Generator extension, 
* Main goal is to generate the links() method instead of using the parent one which parses the .links.ini file
*  = better readability as you can see the links from the table you're working on
*  = better performance as no ini parsing is necessary anymore
* Also creates a reverseLinks() method for reverse links to increase performance in the "related records" block 
* in M_Office_EditRecord()
*
* @package      M
* @subpackage   DB_DataObject_Advgenerator
* @author       Arnaud Sellenet <demental@sat2way.com>
* @copyright    Copyright (c) 2003-2009 Arnaud Sellenet
* @license      http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
* @version      0.1
*/

require_once 'DB/DataObject/Generator.php';

class DB_DataObject_Advgenerator extends DB_DataObject_Generator {
    // ===============================================================
    // = Adds links() and reverselinks() methods into generated code
    // = if not present outside autogenerated input
    // = prevents DB_DataObject from parsing links.ini file each time a new object is factored
    // = @param string $input already present input
    // = @return string generated methods
    // ===============================================================
    
    function derivedHookFunctions($input = "")
    {
      $addlinks = empty($input)?true:eregi('function links *\(.+###END_AUTOCODE',$input)?true:false;
      $addreverselinks = empty($input)?true:eregi('function reverseLinks *\(.+###END_AUTOCODE',$input)?true:false;

        if($addlinks) {
          $l = $this->_getIniLinks($this->table);
          $links="\n";
          if(is_array($l)) {
            foreach($l as $from=>$to) {
                $links.="\t\t\t'$from'=>'$to',\n";
            }
            // This is for i18n plugin. Auto-generate link with the i18n table even if not present in the links.ini
            if(ereg('^(.+)_i18n$',$this->table,$tab)) {
              $links.="\t\t\t'i18n_record_id'=>'".$tab[1].":id',\n";
            }
          }
        }
        if($addreverselinks) {
          $r = $this->_getReverseIniLinks($this->table);
          $reverselinks = "\n";
          if(is_array($r)) {
            foreach($r as $rlink=>$field) {
                $reverselinks.="\t\t\t'$rlink'=>'$field',\n";
            }
          }
        }
        return '
        '.($addlinks?'
    function links() {
        // links generated from .links.ini file
        return array('.$links.'
        );
    }':'').
    ($addreverselinks?'
    function reverseLinks() {
        // reverseLinks generated from .links.ini file
        return array('.$reverselinks.'
        );
    }':'');
    }
    // =============================
    // = Creates reverseLinks array
    // = @param string $table table name
    // = @return array reverselinks
    // =============================
    function _getReverseIniLinks($table) {
            $out = array();
            global $_DB_DATAOBJECT;       
            $lks = $_DB_DATAOBJECT['LINKS'][$this->_database];
            if(!is_array($lks)) {
              return $out;
            }
            foreach($lks as $aTable=>$links) {
                foreach($links as $field=>$link) {
                    $linkSchema = explode(':',$link);
                    if($linkSchema[0]==$table) {
                        $out[$aTable.':'.$field] = $linkSchema[1];
                    }
                }
            }
            return $out;
    }
    // =============================
    // = Creates links array
    // = @param string $table table name
    // = @return array links
    // =============================

    function _getIniLinks($table) {
        global $_DB_DATAOBJECT;       
        if (!isset($_DB_DATAOBJECT['LINKS'][$this->_database])) {
            $schemas = isset($_DB_DATAOBJECT['CONFIG']['schema_location']) ?
                array("{$_DB_DATAOBJECT['CONFIG']['schema_location']}/{$this->_database}.ini") :
                array() ;
                     
            if (isset($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"])) {
                $schemas = is_array($_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]) ?
                    $_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"] :
                    explode(PATH_SEPARATOR,$_DB_DATAOBJECT['CONFIG']["ini_{$this->_database}"]);
            }
                        
             
            
            foreach ($schemas as $ini) {
                
                $links =
                    isset($_DB_DATAOBJECT['CONFIG']["links_{$this->_database}"]) ?
                        $_DB_DATAOBJECT['CONFIG']["links_{$this->_database}"] :
                        str_replace('.ini','.links.ini',$ini);
        
                if (empty($_DB_DATAOBJECT['LINKS'][$this->_database]) && file_exists($links) && is_file($links)) {
                    /* not sure why $links = ... here  - TODO check if that works */
                    $_DB_DATAOBJECT['LINKS'][$this->_database] = parse_ini_file($links, true);
                    if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
                        $this->debug("Loaded links.ini file: $links","links",1);
                    }
                } else {
                    if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
                        $this->debug("Missing links.ini file: $links","links",1);
                    }
                }
            }
        }
        
        
        // if there is no link data at all on the file!
        // we return null.
        if (!isset($_DB_DATAOBJECT['LINKS'][$this->_database])) {
            return '';
        }
        
        if (isset($_DB_DATAOBJECT['LINKS'][$this->_database][$table])) {
            return $_DB_DATAOBJECT['LINKS'][$this->_database][$table];
        }
        
        return array();
        
    }
    /**
     * start()
     * Override original DB/DataObject/Generator.php start() method moving database routing to another method.
     * This allows to use the generator just for retreiving tables used in the project :
     * 
     */
    function start()
    {
      
        $generators = $this->getGenerators();
        $class = get_class($this);
        foreach($generators as $t) {
            foreach(get_class_methods($class) as $method) {
                if (substr($method,0,8 ) != 'generate') {
                    continue;
                }
                $this->debug("calling $method");
                $t->$method();
            }
        }
        $this->debug("DONE\n\n");
    }
    /**
     * generates an array of generators, one for each database in the project
     * @return array of DB_DataObject_Advgenerators
     */
    public function getGenerators()
    {
      $options = &PEAR::getStaticProperty('DB_DataObject','options');
      $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
      $databases = array();
      foreach($options as $k=>$v) {
          if (substr($k,0,9) == 'database_') {
              $databases[substr($k,9)] = $v;
          }
      }

      if (isset($options['database'])) {
          if ($db_driver == 'DB') {
              require_once 'DB.php';
              $dsn = DB::parseDSN($options['database']);
          } else {
              require_once 'MDB2.php';
              $dsn = MDB2::parseDSN($options['database']);
          }

          if (!isset($database[$dsn['database']])) {
              $databases[$dsn['database']] = $options['database'];
          }
      }

      $output = array();
      foreach($databases as $databasename => $database) {
          if (!$database) {
              continue;
          }
          $output[] = $this->factory($database,$databasename,$db_driver);
      }
      return $output;
    }
    /**
    * factory()
    * @access public
    * @return DB_DataObject_Advgenerator instance including tables list for $databasename
    **/
    public function factory($database,$databasename,$db_driver)
    {
      $this->debug("CREATING FOR $databasename\n");
      $class = get_class($this);
      $t = new $class;
      $t->_database_dsn = $database;


      $t->_database = $databasename;
      if ($db_driver == 'DB') {
          require_once 'DB.php';
          $dsn = DB::parseDSN($database);
      } else {
          require_once 'MDB2.php';
          $dsn = MDB2::parseDSN($database);
      }

      if (($dsn['phptype'] == 'sqlite') && is_file($databasename)) {
          $t->_database = basename($t->_database);
      }
      $t->_createTableList();
      return $t;
    }
}

?>